#
# Copyright (C) 2019 Red Hat, Inc.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions of
# the GNU General Public License v.2, or (at your option) any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY expressed or implied, including the implied warranties of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
# Public License for more details.  You should have received a copy of the
# GNU General Public License along with this program; if not, write to the
# Free Software Foundation, Inc., 31 Milk Street #960789 Boston, MA
# 02196 USA.  Any Red Hat trademarks that are incorporated in the
# source code or documentation are not subject to the GNU General Public
# License and may only be used or replicated with the express permission of
# Red Hat, Inc.
#
import os

from pyanaconda.anaconda_loggers import get_module_logger
from pyanaconda.core.configuration.anaconda import conf
from pyanaconda.core.product import get_product_name
from pyanaconda.core.util import execWithRedirect
from pyanaconda.modules.storage.bootloader.base import (
    BootLoader,
    BootLoaderArguments,
    BootLoaderError,
)

log = get_module_logger(__name__)

__all__ = ["EXTLINUX"]


class EXTLINUX(BootLoader):
    name = "EXTLINUX"
    _config_file = "extlinux.conf"
    _config_dir = "/boot/extlinux"

    stage2_format_types = ["ext4", "ext3", "ext2"]
    stage2_device_types = ["partition"]
    stage2_bootable = True

    # The extlinux bootloader doesn't have BLS support, the old grubby is needed
    packages = ["syslinux-extlinux", "grubby-deprecated"]

    @property
    def config_file(self):
        return "%s/%s" % (self._config_dir, self._config_file)

    @property
    def boot_prefix(self):
        """ Prefix, if any, to paths in /boot. """
        if self.stage2_device.format.mountpoint == "/":
            prefix = "/boot"
        else:
            prefix = ""

        return prefix

    def write_config_images(self, config):
        for image in self.images:
            args = BootLoaderArguments()
            args.update(["root=%s" % image.device.fstab_spec, "ro"])
            if image.device.type == "btrfs subvolume":
                args.add("rootflags=subvol=%s" % image.device.name)
            args.update(self.boot_args)
            log.info("bootloader.py: used boot args: %s ", args)

            # extlinux labels cannot have spaces
            label = "%s(%s)" % (self.image_label(image), image.version)
            label = label.replace(" ", "")
            stanza = ("label %(label)s\n"
                      "\tkernel %(boot_prefix)s/%(kernel)s\n"
                      "\tinitrd %(boot_prefix)s/%(initrd)s\n"
                      "\tappend %(args)s\n\n"
                      % {"label": label,
                         "kernel": image.kernel,
                         "initrd": image.initrd,
                         "args": args,
                         "boot_prefix": self.boot_prefix})
            config.write(stanza)

    def write_config_header(self, config):
        header = ("# extlinux.conf generated by anaconda\n\n"
                  "ui menu.c32\n\n"
                  "menu autoboot Welcome to %(productName)s. Automatic boot in # second{,s}. Press a key for options.\n"
                  "menu title %(productName)s Boot Options.\n"
                  "menu hidden\n\n"
                  "timeout %(timeout)d\n"
                  "#totaltimeout 9000\n\n"
                  % {"productName": get_product_name(), "timeout": self.timeout * 10})
        config.write(header)
        if self.default is not None:
            config.write("default %(default)s\n\n" % {"default": self.image_label(self.default).replace(" ", "")})
        self.write_config_password(config)

    def write_config_password(self, config):
        if self.password:
            config.write("menu master passwd %s\n" % self.password)
            config.write("menu notabmsg Press [Tab] and enter the password to edit options")

    def write_config_post(self):
        etc_extlinux = os.path.normpath(conf.target.system_root + "/etc/" + self._config_file)
        if not os.access(etc_extlinux, os.R_OK):
            try:
                os.symlink("../boot/%s" % self._config_file, etc_extlinux)
            except OSError as e:
                log.warning("failed to create /etc/extlinux.conf symlink: %s", e)

    #
    # installation
    #

    def install(self, args=None):
        args = ["--install", self._config_dir]
        rc = execWithRedirect("extlinux", args, root=conf.target.system_root)

        if rc:
            raise BootLoaderError("boot loader install failed")
